package jmine.tec.proxy;

import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Set;

/**
 * 
 * @author takeshi
 * 
 */
public final class SynchronizedProxyFactory {

    /**
     * 
     * 
     */
    private SynchronizedProxyFactory() {
    }

    /**
     * Builds a synchronized proxy around an object on its interfaces. The proxy
     * will hold the lock on the specified object
     * 
     * @param delegate
     *            the Object to witch delegate method calls
     * @param lock
     *            the Object to witch hold the lock
     * @return {@link Object} the proxy
     */
    public static Object proxyFor(final Object delegate, final Object lock) {
        SynchronizedInvocationHandler handler = new SynchronizedInvocationHandler(delegate, lock);
        return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
                findAllInterfaces(delegate), handler);
    }

    /**
     * 
     * @param delegate
     *            an {@link Object}
     * @return array of {@link Class}
     */
    public static Class< ? >[] findAllInterfaces(final Object delegate) {
        Class< ? > type = delegate.getClass();
        Set<Class< ? >> ifs = new HashSet<Class< ? >>();
        while (type != null && !(type.getClass().equals(Object.class))) {
            for (Class< ? > c : type.getInterfaces()) {
                ifs.add(c);
            }
            type = type.getSuperclass();
        }
        return ifs.toArray(new Class[ifs.size()]);
    }

    /**
     * Builds a synchronized proxy around an object on its interfaces. The proxy
     * will hold the lock on the specified object
     * 
     * @param delegate
     *            the Object to witch delegate method calls
     * @return {@link Object} the proxy
     */
    public static Object proxyFor(final Object delegate) {
        return proxyFor(delegate, delegate);
        // SynchronizedInvocationHandler handler = new
        // SynchronizedInvocationHandler(delegate);
        // return
        // Proxy.newProxyInstance(SynchronizedInvocationHandler.class.getClassLoader(),
        // delegate.getClass().getInterfaces(), handler);
    }

}
